﻿using Autofac;
using Autofac.Extensions.DependencyInjection;

namespace In66.Net.Share.Extensions
{
    public static class WebApplicationBuilderExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        private static IDisposable _callbackRegistration;

        /// <summary>
        /// replace placeholder
        /// </summary>
        /// <param name="sections"></param>
        private static void ReplacePlaceholder(IEnumerable<IConfigurationSection> sections)
        {
            var serviceInfo = ServiceInfo.GetInstance();
            foreach (var section in sections)
            {
                var childrenSections = section.GetChildren();
                if (childrenSections.IsBusinessNotNullOrEmpty())
                {
                    ReplacePlaceholder(childrenSections);
                }

                if (section.Value.IsNullOrWhiteSpace())
                {
                    continue;
                }

                var sectionValue = section.Value;
                if (sectionValue.Contains("$SERVICENAME"))
                {
                    section.Value = sectionValue.Replace("$SERVICENAME", serviceInfo.ServiceName);
                }

                if (sectionValue.Contains("$SHORTNAME"))
                {
                    section.Value = sectionValue.Replace("$SHORTNAME", serviceInfo.ShortName);
                }
            }
        }

        /// <summary>
        /// OnSettingConfigurationChanged
        /// </summary>
        /// <param name="state"></param>
        private static void OnSettingConfigurationChanged(object state)
        {
            _callbackRegistration?.Dispose();
            var configuration = state as IConfiguration;
            var changedChildren = configuration.GetChildren();
            var reloadToken = configuration.GetReloadToken();

            ReplacePlaceholder(changedChildren);

            _callbackRegistration = reloadToken.RegisterChangeCallback(OnSettingConfigurationChanged, state);
        }

        /// <summary>
        /// Configure Configuration/ServiceCollection/Logging
        /// <param name="builder"></param>
        /// <param name="serviceInfo"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static WebApplicationBuilder ConfigureDefault(this WebApplicationBuilder builder, IServiceInfo serviceInfo)
        {
            if (builder is null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (serviceInfo is null)
            {
                throw new ArgumentNullException(nameof(serviceInfo));
            }

            var initialData = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("ServiceName", serviceInfo.ServiceName) };
            builder.Configuration.AddInMemoryCollection(initialData);

            #region load config by configpath

            //var configpath = $"{AppContext.BaseDirectory}/appsettings.shared.{builder.Environment.EnvironmentName}.json";

            //builder.Configuration.AddJsonFile(configpath, true, true);

            #endregion

            #region load config by stream

            var assembly = Assembly.GetExecutingAssembly();

            Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.appsettings.shared.json");

            builder.Configuration.AddJsonStream(stream);

            #endregion

            #region load config by consul
            var consulOption = builder.Configuration.GetSection(ConsulConfig.Name).Get<ConsulConfig>();
            if (consulOption.Enabled)
            {
                if (consulOption.ConsulKeyPath.IsNullOrWhiteSpace())
                {
                    throw new NotImplementedException(nameof(consulOption.ConsulKeyPath));
                }

                consulOption.ConsulKeyPath = consulOption.ConsulKeyPath.Replace("$SHORTNAME", serviceInfo.ShortName);
                builder.Configuration.AddConsulConfiguration(consulOption, true);
            }
            #endregion

            OnSettingConfigurationChanged(builder.Configuration);

            //ServiceCollection
            builder.Services.ReplaceConfiguration(builder.Configuration);
            builder.Services.AddSingleton(typeof(IServiceInfo), serviceInfo);
            builder.Services.AddCore(serviceInfo);

            var conf = builder.Configuration;

            //Logging
            builder.Logging.ClearProviders();

            #region GetManifestResourceStream
            //Stream streamserilog = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.serilog.json");
            //var config = new ConfigurationBuilder()
            // .SetBasePath(Directory.GetCurrentDirectory())
            // .AddJsonStream(streamserilog)
            // .Build();

            //builder.Logging.ClearProviders();
            //Serilog.Log.Logger = new LoggerConfiguration()
            //.ReadFrom.Configuration(config)
            //.CreateLogger();
            #endregion

            builder.Host.UseSerilog(dispose: true);

            #region using autofac

            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

            builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
            {
                #region 已经使用DependencyInjection
                ////eventbushandler
                //builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(t => t.Name.EndsWith("EventHandlers")).AsSelf()
                //.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope(); 
                #endregion

            });

            #endregion

            #region 属性注入EasilyNET

            //builder.Host.UseServiceProviderFactory(new PropertyInjectionServiceProviderFactory());

            #endregion

            return builder;
        }

        /// <summary>
        /// BuildServiceProvider
        /// </summary>
        /// <param name="webApplication"></param>
        /// <returns></returns>
        public static WebApplication BuildServiceProvider(this WebApplication webApplication)
        {
            InternalApp.ServiceProvider = webApplication.Services;

            return webApplication;
        }
    }
}
